home *** CD-ROM | disk | FTP | other *** search
/ Tech Arsenal 1 / Tech Arsenal (Arsenal Computer).ISO / tek-15 / ctest257.zip / CCNEW.ASM < prev    next >
Assembly Source File  |  1992-09-24  |  44KB  |  788 lines

  1.              PAGE    ,120
  2.  
  3.             .386p                        ; 80386 code will be used
  4.             .387                         ; need coprocessor, too
  5.  
  6. JMPS        EQU     <JMP SHORT>          ; declare jumps as short
  7. JES         EQU     <JE  SHORT>          ;  since near jumps (+/- 32K)
  8. JBS         EQU     <JB  SHORT>          ;   are default in 386 mode
  9. JNZS        EQU     <JNZ SHORT>          ;    and these cannot execute
  10. JCS         EQU     <JC  SHORT>          ;     on the older CPUs
  11. JZS         EQU     <JZ  SHORT>
  12. JNES        EQU     <JNE SHORT>
  13. JAES        EQU     <JAE SHORT>
  14. JBES        EQU     <JBE SHORT>
  15. JAS         EQU     <JA  SHORT>
  16.  
  17. cpu_i8088   EQU     1
  18. cpu_i8086   EQU     2
  19. cpu_V20     EQU     3
  20. cpu_V30     EQU     4
  21. cpu_i188    EQU     5
  22. cpu_i186    EQU     6
  23. cpu_i286    EQU     7
  24. cpu_i386    EQU     8
  25. cpu_i386sx  EQU     9
  26. cpu_ct38600 EQU     10
  27. cpu_ct38600sx   EQU     11
  28. cpu_486dlc  EQU     12
  29. cpu_486slc  EQU     13
  30. cpu_RapidCAD EQU     14
  31. cpu_i486    EQU     15
  32. cpu_i486SX  EQU     16
  33.  
  34. ndp_NoCopro EQU     0
  35. ndp_Emul    EQU     1
  36. ndp_i8087   EQU     2
  37. ndp_i80C187 EQU     3
  38. ndp_i80287  EQU     4
  39. ndp_i287XL  EQU     5
  40. ndp_i387    EQU     6
  41. ndp_i387sx  EQU     7
  42. ndp_2C87    EQU     8
  43. ndp_3C87    EQU    10
  44. ndp_3C87sx  EQU    11
  45. ndp_82S87   EQU    12
  46. ndp_83D87   EQU    14
  47. ndp_83S87   EQU    15
  48. ndp_83C87   EQU    16
  49. ndp_83C87s  EQU    17
  50. ndp_38700   EQU    18
  51. ndp_38700sx EQU    19
  52. ndp_i387DX  EQU    20
  53. ndp_RapidCAD EQU   21
  54. ndp_i486    EQU    22
  55. ndp_82S87p  EQU    23
  56. ndp_387plus EQU    25
  57. ndp_83S87p  EQU    26
  58. ndp_emc87   EQU    27
  59.  
  60.  
  61. STRT_TIM    MACRO
  62.             MOV     AL, 0B4h             ; timer 2 is
  63.             OUT     43h, AL              ;  programmed as a rate generator
  64.             XOR     AL, AL               ; load zero
  65.             OUT     42h, AL              ; reset
  66.             OUT     42h, AL              ;  timer 2
  67.             ENDM
  68.  
  69. STOP_TIM    MACRO
  70.             MOV     AL, 80h              ; timer 2
  71.             OUT     43h, AL              ;  immediately latched
  72.             IN      AL, 42h              ; read LSB
  73.             MOV     BL, AL               ; save LSB
  74.             IN      AL, 42h              ; read MSB
  75.             MOV     BH, AL               ; save MSB
  76.             NEG     BX                   ; negate for timer count
  77.             ENDM
  78.  
  79.  
  80.  
  81. CODE        SEGMENT BYTE USE16 PUBLIC 'CODE'
  82.  
  83.             ASSUME  CS:CODE
  84.  
  85.             PUBLIC  SpeedTest
  86.  
  87.                                          ; declare parameters
  88.  
  89. Debug_Flag  EQU     [BP+24]              ; <> 0, if debugging output desired
  90. Ext_Flag    EQU     [BP+22]              ; zero, if no extended memory
  91. EMS_Flag    EQU     [BP+20]              ; zero, if no expanded memory
  92. BufferPtr   EQU     [BP+16]              ; buffer for EMS u. EXT test
  93. EMS_Base    EQU     [BP+12]              ; address of EMS-frame
  94. ScreenPtr   EQU     [BP+8]               ; start address of video memory
  95. ResultPtr   EQU     [BP+4]               ; pointer to result struct
  96.  
  97.  
  98.                                          ; declare local variables
  99.  
  100. Stat        EQU     [BP-2]               ; mem for 80x87 status word
  101. Ctrl        EQU     [BP-4]               ; mem for 80x87 control word
  102. GDT         EQU     [BP-52]              ; mem for global descriptor table
  103. SystemStat  EQU     [BP-53]              ; mem for system status
  104. SaveCtrl    EQU     [BP-55]              ; original 80x87 control word
  105.  
  106.  
  107.                                          ; declare result record
  108. CPU_NDP_TYP EQU     [SI]
  109. AAMTime     EQU     [SI+2]
  110. MovEvenTime EQU     [SI+6]
  111. BIOSWrTime  EQU     [SI+8]
  112. MovByteTime EQU     [SI+10]
  113. MovEMSTime  EQU     [SI+12]
  114. MovExtTime  EQU     [SI+14]
  115. ScrFillTime EQU     [SI+16]
  116. Dummy2      EQU     [SI+18]
  117. i87Time     EQU     [SI+20]
  118. i287Time    EQU     [SI+22]
  119. MovDblTime  EQU     [SI+24]
  120.  
  121. SpeedTest   PROC    NEAR
  122.             PUSH    BP                   ; save caller's frame pointer
  123.             MOV     BP, SP               ; make new frame pointer
  124.             SUB     SP, 55               ; alloc mem for local variables
  125.             PUSH    DS                   ; save Turbo Pascal's data segment
  126.             PUSHF                        ; save original flag setting
  127.  
  128. $inittimer: CLI                          ; disable interrupts
  129.             CLD                          ; auto increment for string operations
  130.             IN      AL, 61h              ; port B - system control
  131.             MOV     [SystemStat], AL     ; save system status
  132.             AND     AL, 11111101b        ; clear speaker bit (disable speaker)
  133.             OR      AL, 1                ; turn on bit for timer 2 (enable it)
  134.             CMP     AL, [SystemStat]     ; system already configured correctly ?
  135.             JES     $aam                 ; no need to configure it
  136.             OUT     61h, AL              ; reconfigure system (tmr 2 on,spk off)
  137.  
  138. $aam:       CMP     WORD PTR Debug_Flag,0; debugging output desired ?
  139.             JNZS    $aam1                ; no
  140.             MOV     AH, 9                ; #9, print string
  141.             PUSH    CS                   ; load
  142.             POP     DS                   ;  address of
  143.             MOV     DX, OFFSET CS:$dbg2  ;   debugging message
  144.             INT     21h                  ; call DOS, print debugging message
  145.             JMPS    $aam1                ; skip message text
  146.  
  147. $dbg2       DB      'About to perform AAM speed test', 0Dh, 0Ah ,'$'
  148.  
  149. $aam1:      STRT_TIM                     ; start timer 2
  150.             REPT    200
  151.             AAM                          ; execute 200 AAMs
  152.             ENDM
  153.             STOP_TIM                     ; elapsed time of timer 2 in BX
  154.             LDS     SI, ResultPtr        ; pointer to result struct
  155.             MOV     [AAMTime], BX        ; save time for AAMs
  156.  
  157. $begin_test:CMP     WORD PTR Debug_Flag,0; debugging output desired ?
  158.             JNZS    $cpu_ndptst          ; nope
  159.             MOV     AH, 9                ; #9, print string
  160.             PUSH    CS                   ; load
  161.             POP     DS                   ;  address of
  162.             MOV     DX, OFFSET CS:$dbg1  ;   debugging message
  163.             INT     21h                  ; call DOS, print debugging message
  164.             JMPS    $cpu_ndptst          ; skip message text
  165. $dbg1       DB      'About to perform CPU and NDP test', 0Dh, 0Ah ,'$'
  166.  
  167. $cpu_ndptst:LDS     SI, ResultPtr        ; pointer to result struct
  168.             FNSTCW  [SaveCtrl]           ; save original NDP ctrl word
  169.             PUSH    SP                   ; test updating
  170.             POP     AX                   ;  of stackpointer
  171.             CMP     AX, SP               ; stackpointer updated before push ?
  172.             JES     $286_386             ; no, must be 286, 386 or 486
  173.             MOV     AX, 1                ; try to shift
  174.             MOV     CL, 33               ;  accu 33 times
  175.             SHL     AX, CL               ; shift count masked off ?
  176.             JNZS    $186_188             ; yes, must be 186 or 188
  177.             PUSHA                        ; PUSHA executed on 88/86 as JMP $+2
  178.             STC                          ; carry set if V20 or V30
  179.             JCS     $V20_V30             ; yes, must be V20 or V30
  180.             PUSHF                        ; save flags
  181.             POP     AX                   ; pop flags into AX
  182.             AND     AH, 00FH             ; clear bits 12-15 of flag register
  183.             PUSH    AX                   ; put new flags in stack
  184.             POPF                         ; pop into flag register
  185.             PUSHF                        ; put flags on stack
  186.             POP     AX                   ; get flags
  187.             AND     AH, 0F0H             ; test if all bits
  188.             CMP     AH, 0F0H             ;  in highest nibble set
  189.             JES     $88_86               ; all bits in highest nibble set
  190.             XOR     DL, DL               ; failed all tests, unknown CPU
  191.             JMPS    $copro_test          ; go and test NDP
  192. $88_86:     MOV     DL, cpu_i8088        ; else it's an 88 or 86
  193.             JMPS    $queue_test          ; decide wether 88 or 86
  194. $V20_V30:   POPA                         ; remove pushed bytes
  195.             MOV     DL, cpu_V20          ; it's an V20 or V30
  196.             JMPS    $queue_test          ; decide wether V20 or V30
  197. $186_188:   MOV     DL, cpu_i188         ; 188/186
  198. $queue_test:LEA     BX, [$patch]         ; load patch address into BX
  199.             MOV     BYTE PTR CS:[BX], 42h; preset with opcode for INC DX
  200.             MOV     AL, 90H              ; patch in a NOP (opcode 90h)
  201.             MOV     CL, 31               ; rotate register 31 times to use up
  202.             ROL     AH, CL               ;  time so prefetch queue can be filled
  203.             MOV     BYTE PTR CS:[BX], AL ; insert NOP at label $patch
  204.             NOP                          ; fill
  205.             NOP                          ;  prefetch
  206.             NOP                          ;   queue
  207.             NOP                          ;    with NOPs
  208. $patch:     INC     DX                   ; patched to NOP on i88, i188 and V20
  209. $copro_test:JMP     $ndp_test            ; check for coprocessor
  210. $286_386:   MOV     DL, cpu_i286         ; 286, 386 or 486
  211.             PUSH    7000h                ;  try to set
  212.             POPF                         ;   IOPL and NT fields
  213.             PUSHF                        ;    in bit 12-14
  214.             POP     AX                   ;     of flag register
  215.             TEST    AX, 7000h            ; bits cannot be set in 286 real mode
  216.             JZS     $copro_test          ; bits not set --> 286
  217.             INC     DX                   ; CPU is an 386 (DL = 8) or 486
  218.             MOV     EBX, ESP             ; save current stackpointer to align it
  219.             AND     ESP, 0FFFFFFFCh      ; align stack to avoid AC fault
  220.             PUSHFD                       ; save EFLAGS
  221.             POP     EAX                  ; get EFLAGS from stack
  222.             MOV     ECX, EAX             ; original value of EFLAGS
  223.             XOR     EAX, 40000H          ; toggle AC bit in EFLAGS
  224.             PUSH    EAX                  ; copy new value
  225.             POPFD                        ;  to EFLAGS
  226.             PUSHFD                       ; get new EFLAGS value
  227.             POP     EAX                  ; put into EAX
  228.             XOR     EAX, ECX             ; test if AC bit could be changed
  229.             PUSH    ECX                  ; restore original
  230.             POPFD                        ;  value of EFLAGS
  231.             MOV     ESP, EBX             ; restore original stack pointer
  232.             OR      EAX, EAX             ; EAX = 0 on 386, 40000h on 486
  233.             JNZS    $486_486dlc          ; if <> 0, must be 486/486dlc/486slc
  234. $chk_38600: PUSH    DX                   ; save CPU code
  235.             MOV     ESI, 32              ; 32 trials to check for POPAD bug
  236.             MOV     EAX, 12345678        ; load some value
  237. $trial_loop:MOV     EBX, EAX             ; save value for comparison
  238.             MOV     EDX, 0               ; prepare index and
  239.             MOV     EDI, 0               ;  base register to point to DS:0
  240.             PUSHAD                       ; push all 32-bit registers
  241.             POPAD                        ; pop all 32-bit registers
  242.             MOV     ECX, [EDX+EDI]       ; mem access changes EAX (POPAD bug!)
  243.             CMP     EAX, EBX             ; EAX changed ?
  244.             JNZS    $changed             ; EAX changed -> bug in AMD/Intel 386
  245.             ROL     EAX, 1               ; try next number
  246.             DEC     ESI                  ; decrement trial counter
  247.             JNZS    $trial_loop          ; until 32 trials thru, exits with Z=1
  248. $changed:   POP     DX                   ; restore CPU code
  249.             JNZS    $copro_test          ; EAX changed, must be Intel/AMD 386
  250.             MOV     DL, cpu_ct38600      ; C&T 38600 doesn't have that bug
  251.             JMPS    $copro_test          ; now test for coprocessor
  252. $486_486dlc:MOV     AX, 0AAAAh           ; load initial multiplicand
  253.             MOV     BX, 05555h           ; load multiplicator
  254.             STRT_TIM                     ; start timer 2
  255.             REPT    40                   ; 486: MUL takes 13..18, AAM 15 clocks
  256.             MUL     BX                   ; execute 40 MULs
  257.             ENDM                         ; 486DLC: MUL takes 3, AAM 17 clocks
  258.             STOP_TIM                     ; elapsed time of timer 2 in BX
  259.             ADD     BX, BX               ; time for 80 MULs
  260.             ADD     BX, BX               ; time for 160 MULs
  261.             ADD     BX, BX               ; time for 320 MULs
  262.             CMP     BX, [AAMTime]        ; time for 320 MULs>time for 200 AAMs ?
  263.             JAS     $486                 ; yes, 486 has slow MUL
  264.             MOV     DL, cpu_486dlc       ; no, fast MUL -> 486DLC/486SLC
  265.             JMPS    $ndp_test            ; now test for coprocessors
  266. $486:       MOV     DL, cpu_i486         ; it's a 486 (CPU = 15)
  267. $ndp_test:  XOR     DH, DH               ; assume no coprocessor
  268.             XOR     AX, AX               ; clear register
  269.             OUT     0F0h, AL             ; clear error signal of coprocessor
  270.             FNINIT                       ; initialize coprocessor
  271.             MOV     [Ctrl], AX           ; clear status variable
  272.             NOT     AX                   ; load all 1's
  273.             MOV     [Stat], AX           ; initialize status variable to all 1's
  274.             FNSTCW  [Ctrl]               ; store NDP control word
  275.             MOV     AX, [Ctrl]           ; get control word
  276.             AND     AX, 0F3Fh            ; extract RC, PC and exception masks
  277.             CMP     AX, 033Fh            ; RC=0, PC=3, masks=3F ?
  278.             JNES    $chk_486sx           ; no -> no coprocessor present
  279.             FNSTSW  [Stat]               ; store NDP status
  280.             TEST    WORD PTR [Stat],383Fh; stack top & exceptions must be clear
  281.             JNZS    $chk_486sx           ; ST & exceptions not clear -> no NDP
  282.             MOV     DH, ndp_Emul         ; coprocessor is at least emulator (=1)
  283.             CMP     DL, cpu_i286         ; is CPU 80286 or higher ?
  284.             JBS     $no_emulat           ; no, emulation impossible
  285.             SMSW    AX                   ; get machine status word
  286.             TEST    AL, 4                ; test if EM bit of MSW set
  287.             JZS     $no_emulat           ; not set -> no NDP emulation
  288. $chk_486sx: CMP     DL, cpu_i486         ; CPU = Intel 486 and no/emulated copro ?
  289.             SBB     DL, -1               ; yes, CPU is 486sx (increment DL)
  290.             JMP     $ndp_exit            ; no further NDP checking
  291. $no_emulat: MOV     DH, ndp_i8087        ; coprocessor is at least 8087 (=2)
  292.             FLD1                         ; load 1.0
  293.             WAIT                         ; needed for 8087
  294.             FLDZ                         ; load 0.0
  295.             WAIT                         ; needed for 8087
  296.             FDIV                         ; 1.0 / 0.0 = +infinity
  297.             WAIT                         ; needed for 8087
  298.             FLD     ST(0)                ; duplicate +infinity
  299.             WAIT                         ; needed for 8087
  300.             FCHS                         ; generate -infinity
  301.             WAIT                         ; needed for 8087
  302.             FCOMPP                       ; compare infinities and clear NDP stk
  303.             WAIT                         ; needed for 8087
  304.             FSTSW   WORD PTR [Stat]      ; save condition codes
  305.             MOV     AX, [Stat]           ; load condition codes
  306.             SAHF                         ; transfer into CPU flags
  307.             JNES    $187_387             ; 187, C287 or 387 if numbers not equal
  308.             CMP     DL, cpu_i286         ; is CPU >= 286 ?
  309.             JBS     $ndp_exit1           ; no, coprocessor is 8087
  310.             MOV     DH, ndp_i80287       ; coprocessor is 287
  311.             JMPS    $chk_iit             ; check for IIT coprocessors
  312. $187_387:   CMP     DL, cpu_i286         ; is CPU >= 286 ?
  313.             JAES    $C287_387            ; yes, NDP is either C287, 287XL or 387
  314.             MOV     DH, ndp_i80C187      ; coprocessor is 187
  315.             JMPS    $ndp_exit1           ; store CPU and NDP code
  316. $C287_387:  CMP     DL, cpu_i386         ; is CPU >= 386 ?
  317.             JAES    $387_486             ; yes, NDP is 387 or 387sx, 486
  318.             MOV     DH, ndp_i287XL       ; coprocessor is C287
  319.             JMPS    $chk_iit             ; check for IIT coprocessors
  320. $387_486:   CMP     DL, cpu_i486         ; is CPU >= 486 ?
  321.             JAES    $i486                ; yes, NDP is 486 / 487
  322.             MOV     DH, ndp_i387         ; coprocessor is 387 or 387sx
  323.             JMPS    $chk_iit             ; check for IIT coprocessors
  324. $i486:      MOV     DH, ndp_i486         ; NDP = 486 / 487
  325. $ndp_exit1: JMP     $ndp_exit            ; no further tests required
  326. $chk_iit:   FNINIT                       ; initialize coprocessor
  327.             FLD     CS:[$denormal]       ; load denormal number
  328.             FADD    ST(0), ST            ; result is zero on IIT
  329.             FNSTSW  AX                   ; get status of NDP into AX
  330.             TEST    AL, 02h              ; test if denormal exception flag set
  331.             JNZS    $chk_ulsi            ; Intel NDPs signal denormal exception
  332.             ADD     DH,ndp_2c87-ndp_i80287;set IIT coprocessor types
  333.             JMPS    $ndp_exit1           ; coprocessor type found
  334. $chk_ulsi:  CMP     DL, cpu_i386         ; CPU >= 386 ?
  335.             JBS     $chk_cyrix1          ; no, can not be ULSI
  336.             FNINIT                       ; initialize coprocessor
  337.             FLDCW   CS:[$53bit_prec]     ; PC => 53 bits (ULSI ignores PC)
  338.             FLD     TBYTE PTR CS:[$op1]  ; load 2-epsilon
  339.             FLD1                         ; load 1
  340.             FADDP   ST(1), ST            ; result should be 3 and PE raised
  341.             FSTP    TBYTE PTR [GDT]      ; store result, clear NDP stack
  342.             FNSTSW  AX                   ; get coprocessor status word
  343.             TEST    AL, 20h              ; precision exception ?
  344.             JNZS    $chk_cyrix1          ; ULSI computes 64 bit result, no PE!
  345.             FWAIT                        ; make sure result is stored
  346.             CMP     BYTE PTR [GDT], 0F8h ; check least significant mantissa bits
  347.             JNES    $chk_cyrix1          ; not expected result for ULSI
  348.             CMP     BYTE PTR [GDT+9], 40h; check exponent hi-byte
  349.             JNES    $chk_cyrix1          ; not expected result for ULSI
  350.             ADD     DH,ndp_83C87-ndp_i387; set ULSI types
  351.             JMPS    $ndp_exit1           ; done
  352. $chk_cyrix1:FNINIT                       ; initialize coprocessor
  353.             FLD     TBYTE PTR CS:[$nan]  ; load positive NaN
  354.             FLD     ST(0)                ; duplicate NaN
  355.             FCHS                         ; make negative NaN
  356.             FPATAN                       ; ATAN (-NaN, +NaN) should return +NaN
  357.             FSTP    TBYTE PTR [GDT]      ; store result, clear NDP stack
  358.             FWAIT                        ; wait until result is stored
  359.             CMP     BYTE PTR [GDT+9], 7Fh; Cyrix ret. +NAN (7F),Intel -NAN (FF)
  360.             JNES    $chk_ct              ; Intel coprocessor
  361. $chk_emc87: FNSTCW  [Ctrl]               ; store control word
  362.             OR      BYTE PTR [Ctrl+1],80h; set msb of control word
  363.             FLDCW   [Ctrl]               ; and load back into coprocessor
  364.             FSTCW   [Ctrl]               ; store control word again
  365.             FWAIT                        ; wait until stored
  366.             TEST    BYTE PTR [Ctrl+1],80h; could msb be set ?
  367.             JZS     $no_emc              ; no -> no EMC87
  368.             MOV     DH, ndp_emc87        ; set NDP type to EMC87
  369.             JMPS    $ndp_exit            ; done
  370. $no_emc:    ADD     DH,ndp_82S87-ndp_i80287; set old Cyrix types
  371.             FLD1                         ; load 1.0
  372.             FLD     ST(0)                ; load another 1.0
  373.             FYL2XP1                      ; compute 1.0*ld(2.0)
  374.             FLD1                         ; compare result with 1.0
  375.             FCOMPP                       ; new Cyrix copros have correct result
  376.             FNSTSW  AX                   ; store coprocessor condition bits
  377.             SAHF                         ; transfer to CPU flags
  378.             JNES    $ndp_exit            ; if incorrect result, not new Cyrix
  379.             ADD     DH,ndp_82S87p-ndp_82S87; set NDP-type to new Cyrix types
  380.             JMPS    $ndp_exit            ; done
  381. $chk_ct:    CMP     DL, cpu_i386         ; CPU >= 386 ?
  382.             JBS     $chk_387DX           ; no, can not be C&T
  383.             FNINIT                       ; initialize coprocessor
  384.             FLDPI                        ; load pi
  385.             F2XM1                        ; 2**(pi)-1=pi/2, argument out of range
  386.             FLD1                         ; load 1.0
  387.             FCHS                         ; -1.0
  388.             FLDPI                        ; load pi
  389.             FSCALE                       ; pi/2
  390.             FSTP    ST(1)                ; pi/2
  391.             FCOMPP                       ; 2**(pi)-1=pi/2 ?
  392.             FSTSW   AX                   ; save condition codes
  393.             SAHF                         ; transfer to CPU flags
  394.             JNES    $chk_387DX           ; not equal, not C&T
  395.             ADD     DH,ndp_38700-ndp_i387; set C&T types
  396.             JMPS    $ndp_exit            ; done
  397. $chk_387DX: CMP     DH, ndp_i387         ; Intel 387 ?
  398.             JNES    $ndp_exit            ; no, done. Only want to check i387
  399.             FNINIT                       ; initialize coprocessor
  400.             FLD1                         ; load 1.0
  401.             FCHS                         ; -1.0
  402.             FXTRACT                      ; split into mantissa and exponent(0)
  403.             FSTP    ST(0)                ; pop mantissa
  404.             FXAM                         ; look at sign of exponent
  405.             FNSTSW  AX                   ; store status word
  406.             AND     AH, 2                ; C1 set (negative) on old 387
  407.             FSTP    ST(0)                ; clear coprocessor stack
  408.             JNZS    $ndp_exit            ; C1 set, no 387DX
  409.             MOV     DH, ndp_i387DX       ; set NDP-type to 387DX
  410.             FNINIT                       ; initialize coprocessor
  411.             FBSTP   TBYTE PTR [GDT]      ; store BCD indefinite
  412.             CMP     BYTE PTR [GDT+7],0C0h; RapidCAD stores C0h, 387DX stores 80h
  413.             JNES    $ndp_exit            ; no RapidCAD
  414.             MOV     DX, ndp_RapidCAD*100H+cpu_RapidCAD; RapidCAD (NDP=21,CPU=14)
  415. $ndp_exit:  LDS     SI, ResultPtr        ; pointer to result record
  416.             MOV     [SI], DX             ; save CPU and NDP types
  417.             JMPS    $moveeven            ; skip over test data for NDP check
  418.  
  419. $denormal   DT      1
  420. $nan        DB      0FFh, 0FFh, 0FFh, 0FFh, 0FFh, 0FFh, 0FFh, 0FFh, 0FFh, 07Fh
  421. $op1        DB      0F0h, 0FFh, 0FFh, 0FFh, 0FFh, 0FFh, 0FFh, 0FFh, 0FFh, 03Fh
  422. $53bit_prec DW      027Fh
  423.  
  424.  
  425. $moveeven:  CMP     WORD PTR Debug_Flag,0; debugging output desired ?
  426.             JNZS    $moveeven1           ; no
  427.             MOV     AH, 9                ; #9, print string
  428.             PUSH    CS                   ; load
  429.             POP     DS                   ;  address of
  430.             MOV     DX, OFFSET CS:$dbg3  ;   debugging message
  431.             INT     21h                  ; call DOS, print debugging message
  432.             JMPS    $moveeven1           ; skip message text
  433. $dbg3       DB      'About to perform MOVEEVEN memory speed test', 0Dh, 0Ah ,'$'
  434.  
  435. $moveeven1: MOV     AX, DS               ; set up segment registers
  436.             MOV     ES, AX               ;  for memory move
  437.             XOR     SI, SI               ; offset in both segments
  438.             MOV     DI, SI               ;  is zero
  439.             MOV     CX, 5000             ; move 5000
  440.             REP     MOVSW                ;  words
  441.             STRT_TIM                     ; start timer 2
  442.             XOR     SI, SI               ; offset in both segments
  443.             MOV     DI, SI               ;  is zero
  444.             MOV     CX, 5000             ; move 5000
  445.             REP     MOVSW                ;  words
  446.             STOP_TIM                     ; elapsed time of timer 2 in BX
  447.             LDS     SI, ResultPtr        ; pointer to result record
  448.             MOV     [SI+6], BX           ; save MoveEvenTime
  449.  
  450.  
  451. $movebyte:  CMP     WORD PTR Debug_Flag,0; debugging output desired ?
  452.             JNZS    $movebyte1           ; no
  453.             MOV     AH, 9                ; #9, print string
  454.             PUSH    CS                   ; load
  455.             POP     DS                   ;  address of
  456.             MOV     DX, OFFSET CS:$dbg5  ;   debugging message
  457.             INT     21h                  ; call DOS, print debugging message
  458.             JMPS    $movebyte1           ; skip message text
  459. $dbg5       DB      'About to perform MOVEBYTE wait state test', 0Dh, 0Ah ,'$'
  460.  
  461. $movebyte1: MOV     AX, DS               ; set up segment registers
  462.             MOV     ES, AX               ;  for memory move
  463.             MOV     SI, 1                ; offset in source and destination
  464.             MOV     DI, SI               ;  segment is odd
  465.             STRT_TIM                     ; start timer 2
  466.             MOV     CX, 5000             ; move 5000
  467.             REP     MOVSB                ;  bytes
  468.             STOP_TIM                     ; elapsed time of timer 2 in BX
  469.             LDS     SI, ResultPtr        ; pointer to result struct
  470.             MOV     [SI+10], BX          ; save MoveByteTime
  471.  
  472. $movedouble:CMP     WORD PTR Debug_Flag,0; debugging output desired ?
  473.             JNZS    $movedoubl1          ; no
  474.             MOV     AH, 9                ; #9, print string
  475.             PUSH    CS                   ; load
  476.             POP     DS                   ;  address of
  477.             MOV     DX, OFFSET CS:$dbg6  ;   debugging message
  478.             INT     21h                  ; call DOS, print debugging message
  479.             JMPS    $movedoubl1          ; skip message text
  480. $dbg6       DB      'About to perform MOVEDOUBLE 386sx test', 0Dh, 0Ah ,'$'
  481.  
  482. $movedoubl1:LDS     SI, ResultPtr        ; pointer to result struct
  483.             CMP     BYTE PTR [SI],cpu_i386; CPU = iAPX 386 or i486 ?
  484.             JBS     $move_ems            ; no 386/486
  485.             MOV     AX, DS               ; load segment registers
  486.             MOV     ES, AX               ;  for memory move
  487.             XOR     SI, SI               ; offset in source and destination
  488.             MOV     DI, SI               ;  segment is 0
  489.             MOV     CX, 5000             ; move 5000
  490.             REP     MOVSD                ;  double words
  491.             STRT_TIM                     ; start timer 2
  492.             XOR     SI, SI               ; offset in source and destination
  493.             MOV     DI, SI               ;  segment is 0
  494.             MOV     CX, 5000             ; move 5000
  495.             REP     MOVSD                ;  double words
  496.             STOP_TIM                     ; elapsed time for 2 in BX
  497.             LDS     SI, ResultPtr        ; pointer to result struct
  498.             MOV     [SI+24], BX          ; save MoveDouble-Time
  499.  
  500. $chk_386sx: CMP     BYTE PTR [SI], cpu_i486 ; CPU >= i486 ?
  501.             JAES    $move_ems            ; yes, no need to test for 386sx
  502.             MOV     AX, [SI+6]           ; AX = MoveWord-Time
  503.  
  504.             XCHG    AX, BX               ; AX = MoveDouble-Time,BX=MoveWord-Time
  505.             SUB     AX, BX               ; MoveDTime - MoveWTime
  506.             ADD     AX, AX               ; 2 * (MoveDTime - MoveWTime)
  507.             CWD                          ; compute
  508.             XOR     AX, DX               ;  Abs (2 * (MoveDoubleTime -
  509.             SUB     AX, DX               ;   MoveWordTime))
  510.             CMP     BX, AX               ; Abs(2*(MoveDTime-MoveWTime))>MoveWTime ?
  511.             ADC     WORD PTR [SI], 0     ; CPU type = 386sx if true
  512.             CMP     BYTE PTR [SI],cpu_ct38600sx; CPU = C&T 38600sx ?
  513.             JNES    $move_ems            ; no
  514.             MOV     BYTE PTR [SI],cpu_i386sx; POPAD test unreliable for 386sx,
  515.                                          ; reset to Intel 386 since more likely
  516.  
  517. $move_ems:  CMP     WORD PTR Debug_Flag,0; debugging output desired ?
  518.             JNZS    $move_ems1           ; no
  519.             MOV     AH, 9                ; #9, print string
  520.             PUSH    CS                   ; load
  521.             POP     DS                   ;  address of
  522.             MOV     DX, OFFSET CS:$dbg7  ;   debugging message
  523.             INT     21h                  ; call DOS, print debugging message
  524.             JMPS    $move_ems1           ; skip message text
  525. $dbg7       DB      'About to perform EMS memory access test', 0Dh, 0Ah ,'$'
  526.  
  527. $move_ems1: CMP     BYTE PTR EMS_Flag, 0 ; does EMS memory exist ?
  528.             JES     $move_ext            ; no, skip this test
  529.             MOV     AH, 43h              ; #43, allocate page
  530.             MOV     BX, 1                ;  one page
  531.             INT     67h                  ; call EMM-driver (handle in DX)
  532.             MOV     AH, 47h              ; #47, save page map
  533.             INT     67h                  ; call EMM-driver
  534.             MOV     AH, 44h              ; #44, map page
  535.             MOV     AL, 0                ; physical page 0
  536.             MOV     BX, 0                ; logical page 0
  537.             INT     67h                  ; call EMM-driver
  538.             LES     DI, BufferPtr        ; pointer to buffer
  539.             MOV     CX, 5000             ; 5000 words
  540.             LDS     SI, ResultPtr        ; pointer to result struct
  541.             STRT_TIM                     ; start timer 2
  542.             CMP     BYTE PTR [SI], cpu_i386 ; processor 386 or higher?
  543.             LDS     SI, EMS_Base         ; pointer to EMS page frame
  544.             JAES    $is_386              ; is a 386/486
  545.             REP     MOVSW                ; move words from page frame to buffer
  546.             JMPS    $no_386              ; was no 386/486
  547. $is_386:    MOV     CX, 4000             ; 4000 double words = 1 EMS page
  548.             REP     MOVSD                ; move 4000 double words
  549. $no_386:    STOP_TIM                     ; elapsed time of timer 2 in BX
  550.             LDS     SI, ResultPtr        ; pointer to result struct
  551.             MOV     [SI+12], BX          ; save MoveEMSTime
  552.             MOV     AH, 48h              ; #48, restore map
  553.             INT     67h                  ; call EMM-driver
  554.             MOV     AH, 45h              ; #45, deallocate page
  555.             INT     67h                  ; call EMM-driver
  556.  
  557. $move_ext:  CMP     WORD PTR Debug_Flag,0; debugging output desired ?
  558.             JNZS    $move_ext1           ; no
  559.             MOV     AH, 9                ; #9, print string
  560.             PUSH    CS                   ; load
  561.             POP     DS                   ;  address of
  562.             MOV     DX, OFFSET CS:$dbg8  ;   debugging message
  563.             INT     21h                  ; call DOS, print debugging output
  564.             JMPS    $move_ext1           ; skip message text
  565. $dbg8       DB      'About to perform extended memory access test', 0Dh, 0Ah ,'$'
  566.  
  567. $move_ext1: CMP     BYTE PTR Ext_Flag, 0 ; does extended memory exist ?
  568.             JES     $screenfill          ; no, skip test
  569.             STRT_TIM                     ; start timer 2
  570.             XOR     AX, AX               ; load zero
  571.             MOV     BX, SS               ; load
  572.             MOV     ES, BX               ;  address
  573.             LEA     DI, GDT              ;   of GDT
  574.             MOV     CX, 30h              ; 30h bytes long
  575.             REP     STOSB                ; init with 0
  576.             LEA     SI, GDT              ; reload address of GDT
  577.             MOV     WORD PTR GDT+10H,10000; number of bytes to move
  578.             MOV     WORD PTR GDT+12H, 0  ; source:
  579.             MOV     BYTE PTR GDT+14H, 10H;  100000H (start of extended memory)
  580.             MOV     BYTE PTR GDT+15H, 93H; access rights (read/write)
  581.             MOV     WORD PTR GDT+18H,10000; number of bytes to move
  582.             LDS     DI, BufferPtr        ; load pointer to buffer
  583.             MOV     AX, DS               ; load pointer into DX:AX
  584.             XOR     DX, DX               ; linearize
  585.             SHL     AX, 1                ;  address,
  586.             RCL     DX, 1                ;   32 bit result
  587.             SHL     AX, 1                ;    in
  588.             RCL     DX, 1                ;     DX:AX
  589.             SHL     AX, 1                ;
  590.             RCL     DX, 1                ;
  591.             SHL     AX, 1                ;
  592.             RCL     DX, 1                ;
  593.             ADD     AX, DI               ;
  594.             ADC     DX, 0                ;
  595.             MOV     WORD PTR GDT+1AH, AX ; destination:
  596.             MOV     BYTE PTR GDT+1CH, DL ;  buffer
  597.             MOV     BYTE PTR GDT+1DH, 93H; access rights (read/write)
  598.             MOV     AH, 87h              ; move from extended memory
  599.             MOV     CX, 5000             ; move 5000 words from ext to buffer
  600.             INT     15H                  ; call AT-BIOS
  601.             STOP_TIM                     ; elapsed time of timer 2 in BX
  602.             LDS     SI, ResultPtr        ; pointer to result record
  603.             MOV     [SI+14], BX          ; save MoveExtTime
  604.  
  605. $screenfill:CMP     WORD PTR Debug_Flag,0; debugging output desired ?
  606.             JNZS    $screenfil1          ; no
  607.             MOV     AH, 9                ; #9, print string
  608.             PUSH    CS                   ; load
  609.             POP     DS                   ;  address of
  610.             MOV     DX, OFFSET CS:$dbg9  ;   debugging message
  611.             INT     21h                  ; call DOS, print string
  612.             JMPS    $screenfil1          ; skip message text
  613. $dbg9       DB      'About to perform SCREENFILL test', 0Dh, 0Ah ,'$'
  614.  
  615. $screenfil1:LES     DI, ScreenPtr        ; pointer to start of video memory
  616.             STRT_TIM                     ; start timer 2
  617.             MOV     CX, 5000             ; fill 5000 bytes
  618.             REP     STOSB                ;  of video memory
  619.             STOP_TIM                     ; elapsed time for timer 2 in BX
  620.             LDS     SI, ResultPtr        ; pointer to result struct
  621.             MOV     [SI+16], BX          ; save ScreenFillTime
  622.  
  623. $bios_write:CMP     WORD PTR Debug_Flag,0; debugging output desired ?
  624.             JNZS    $bios_writ1          ; no
  625.             MOV     AH, 9                ; #9, print string
  626.             PUSH    CS                   ; load
  627.             POP     DS                   ;  address of
  628.             MOV     DX, OFFSET CS:$dbg4  ;   debugging message
  629.             INT     21h                  ; call DOS, print debugging message
  630.             JMPS    $bios_writ1          ; skip message text
  631. $dbg4       DB      'About to perform BIOS_WRITE screen speed test', 0Dh, 0Ah ,'$'
  632.  
  633. $bios_writ1:STRT_TIM                     ; start timer 2
  634.             MOV     SI, 20               ; write 20 characters
  635. $out_loop:  MOV     AX, 0920h            ; #9, write char and attribute
  636.             MOV     BX, 0                ; page 0, attribute = blank
  637.             MOV     CX, 1                ; write one character at a time
  638.             INT     10H                  ; call video-BIOS
  639.             DEC     SI                   ; loop over number of chars
  640.             JNZS    $out_loop            ; until all 20 chars output
  641.             STOP_TIM                     ; elapsed time of timer 2 in BX
  642.             LDS     SI, ResultPtr        ; pointer to result struct
  643.             MOV     [SI+8], BX           ; save BIOS-WriteTime
  644.  
  645. $speed87:   CMP     WORD PTR Debug_Flag,0; debugging output desired ?
  646.             JNZS    $speed871            ; no
  647.             MOV     AH, 9                ; #9, print string
  648.             PUSH    CS                   ; load
  649.             POP     DS                   ;  address of
  650.             MOV     DX, OFFSET CS:$dbg10 ;   debugging message
  651.             INT     21h                  ; call DOS, print debugging message
  652.             JMPS    $speed871            ; skip message text
  653. $dbg10      DB      'About to perform NDP speed test', 0Dh, 0Ah ,'$'
  654.  
  655. $speed871:  LDS     SI, ResultPtr        ; pointer to result struct
  656.             CMP     BYTE PTR [SI+1], 1   ; real coprocessor present ?
  657.             JAS     $cont_87             ; yes, do coprocessor tests
  658.             JMP     $no_fpu              ; no, done
  659. $cont_87:   WAIT                         ; for 8087
  660.             FNINIT                       ; initialize coprocessor
  661.             WAIT                         ; for 8087
  662.             FLD1                         ; load 1
  663.             STRT_TIM                     ; start timer 2
  664.             REPT    40                   ; do following 40 times:
  665.             WAIT                         ;  needed on 8087
  666.             FSQRT                        ;  compute Sqrt(1)
  667.             ENDM
  668.             FWAIT                        ; wait until coprocessor done
  669.             STOP_TIM                     ; time for 40 sqrt computations on BX
  670.             LDS     SI, ResultPtr        ; pointer to result struct
  671.             MOV     [SI+20], BX          ; save 87-Time
  672.  
  673. $speed287:  FNINIT                       ; initialize coprocessor
  674.             FLD1                         ; load 1
  675.             STRT_TIM                     ; start timer 2
  676.             REPT    40                   ; do following 40 times:
  677.             NOP                          ;  needed on 8087
  678.             FSQRT                        ;  compute Sqrt(1)
  679.             ENDM
  680.             STOP_TIM                     ; time for 40 sqrt computations in BX
  681.             LDS     SI, ResultPtr        ; pointer to result struct
  682.             MOV     [i287Time], BX       ; save 287-Time
  683.             MOV     CX, [SI]             ; get CPU (CL) and NDP (CH)
  684. ;            CMP     CL, cpu_486slc       ; CPU > 486slc ?
  685. ;            JAS     $store_typ1          ; yes, 486/486SX, no further testing
  686. ;            CMP     CL, cpu_i386         ; CPU < 386 ?
  687. ;            JBS     $store_typ1          ; yes, 287 types already checked, done
  688. ;            CMP     CH, ndp_i387         ; is NDP one of IIT, ULSI, CYRIX ?
  689. ;            JAS     $chk_387pls          ; yes, check for Cyrix 387+
  690. ;            JBS     $store_typ1          ; 80386 w/ 80287, done
  691. ;            JAES    $chk_RCAD            ; check for RapidCAD
  692. ;$store_typ1:JMP     $store_type          ; done, store CPU/NDP type
  693. ;$chk_387pls:JMP     $chk_387p            ; check for Cyrix 387+
  694. ;$chk_RCAD:  FNINIT                       ; initialize coprocessor
  695. ;            STRT_TIM                     ; start timer
  696. ;            REPT    15                   ; do following 15 times:
  697. ;            FLDL2T                       ;  load Log2(10)
  698. ;            FSTP    TBYTE PTR [GDT]      ;   and store as EXTENDED
  699. ;            ENDM
  700. ;            STOP_TIM                     ; stop timer, count in BX
  701. ;            ADD     BX, BX               ; 30 *store time
  702. ;            ADD     BX, BX               ; 60 *store time
  703. ;            ADD     BX, BX               ; 120*store time
  704. ;            CMP     BX, [i287Time]       ; 120*store time < 40 * SQRT-287 time ?
  705. ;            JAS     $chk_387p            ; no -> slow stores: no RapidCAD
  706. ;            MOV     CX, ndp_RapidCAD*100H+cpu_RapidCAD; RapidCAD (NDP=21,CPU=14)
  707. ;            JMPS    $store_type          ; no further tests needed
  708. ;$chk_387p:;  CMP     CH, ndp_83D87        ; Cyrix 387?
  709.           ;  JNES    $chk_387sx           ; no, check for SX types
  710.           ;  MOV     BX, [i287Time]       ; SQRT-287 time
  711.           ;  MOV     DX, [AAMTime]        ; AAM-time
  712.           ;  MOV     AX, BX               ; 40 * SQRT-287 time
  713.           ;  SHR     AX, 1                ; 20 * SQRT-287 time
  714.           ;  ADD     AX, BX               ; 60 * SQRT-287 time
  715.           ;  CMP     AX, DX               ; 60 * SQRT-287 < 200 * AAM ?
  716.           ;  JBS     $chk_387sx           ; yes, Fasmath 83D87
  717.           ;  MOV     CH, ndp_387plus      ; no, slower: 387+
  718. $chk_387sx: CMP     CL, cpu_i386sx       ; CPU = 80386sx ?
  719.             JES     $has_387sx           ; is SX
  720.             CMP     CL, cpu_ct38600sx    ; CPU = 38600sx ?
  721.             JES     $has_387sx           ; is SX
  722.             CMP     CL, cpu_486slc       ; CPU = 486SLC ?
  723.             JNES    $no_387sx            ; no SX
  724. $has_387sx: INC     CH                   ; set SX versions of 387 coprocessors
  725. ;            JMPS    $store_type          ; SX-types certainly no DX-types
  726. $no_387sx: ; CMP     CH, ndp_i387         ; NDP = Intel 387 ?
  727. ;            JNES    $store_type          ; no, check for 387DX makes no sense
  728. ;$chk_387dx: FNINIT                       ; initialize coprocessor
  729.            ; FLD1                         ; load
  730.            ; FLD1                         ;  three
  731.            ; FLD1                         ;   1.0's
  732.            ; STRT_TIM                     ; start timer 2
  733.            ; FBSTP   TBYTE PTR [GDT]      ; store 1
  734.            ; FBSTP   TBYTE PTR [GDT]      ;  three times in
  735.            ; FBSTP   TBYTE PTR [GDT]      ;   BCD format
  736.            ; MOV     AL, 80h              ; latch
  737.            ; OUT     43h, AL              ;  timer 2
  738.            ; IN      AL, 42h              ; read LSB of timer value
  739.            ; MOV     DL, AL               ; save LSB
  740.            ; IN      AL, 42h              ; read MSB of timer value
  741.            ; MOV     DH, AL               ; save MSB
  742.            ; NEG     DX                   ; elapsed time of timer 2 in DX
  743.            ; ADD     DX, DX               ; time for six FBSTPs
  744.            ; ADD     DX, DX               ; time for twelve FBSTPs
  745.            ; CMP     DX, [i287Time]       ; 12 * FBSTP-time < 40 * SQRT-time ?
  746.            ; JAS     $store_type          ; no -> can not be 387DX
  747.            ; MOV     CH, ndp_i387DX       ; set NDP-type to 387DX
  748. $store_type:MOV     [SI], CX             ; save CPU and NDP type
  749.             CMP     CL, cpu_i286         ; CPU higher than 286 ?
  750.             JBES    $no_weitek           ; no, Weitek only available for 386/486
  751.             PUSH    SI                   ; save pointer
  752.             PUSH    DS                   ;  to result struct
  753.             XOR     EAX, EAX             ; zero everything in result register
  754.             INT     11h                  ; do equipment check
  755.             TEST    EAX, 01000000h       ; check bit 24, set if Weitek present
  756.             POP     DS                   ; restore pointer
  757.             POP     SI                   ;  to result struct
  758.             JES     $no_weitek           ; bit not set, no Weitek
  759.             OR      BYTE PTR [SI+1], 80h ; set Weitek flag in coprocessor type
  760. $no_weitek: FNINIT                       ; reprogram
  761.             FLDCW   [SaveCtrl]           ;  original NDP control word
  762.  
  763. $no_fpu:    MOV     AL, [SystemStat]     ; get original system status
  764.             OUT     61h, AL              ;  and restore it
  765.  
  766. $ende:      POPF                         ; restore original flag settings
  767.             POP     DS                   ; restore Turbo Pascal's data segment
  768.             MOV     SP, BP               ; discard local variables
  769.             POP     BP                   ; restore caller's frame pointer
  770.             RET     22                   ; return, pop parameters
  771.  
  772. COMMENT #
  773.             MOV     EAX, 0417A000h       ; test if early 80386
  774.             MOV     ECX, 00000081h       ;  processor with 32 multiplication bug
  775.             MUL     ECX
  776.             CMP     EDX, 00000002h
  777.             JNZS    $mul_err
  778.             CMP     EAX, 0FE7A000h
  779.             JNZS    $mul_err
  780. #
  781.  
  782. SpeedTest   ENDP
  783.  
  784.  
  785. CODE        ENDS
  786.  
  787.             END
  788.